import { Manager } from 'socket.io-client';
import { apiClient } from '../services/apiClient';

interface DeviceStatusChange {
  deviceId: string;
  status: 'online' | 'offline';
  timestamp: string;
  lastHeartbeat?: string;
  temperature?: number;
  humidity?: number;
}

interface DeviceDataUpdate {
  deviceId: string;
  timestamp: string;
  temperature?: number;
  humidity?: number;
}

interface DeviceStatusBroadcast {
  deviceId: string;
  status: 'online' | 'offline';
  timestamp: string;
  metadata: {
    ipAddress?: string;
    firmwareVersion?: string;
    lastSeen: string;
    connectionType?: 'wifi' | 'ethernet' | 'cellular';
    signalStrength?: number;
  }
}

type WebSocketMessage = {
  type: 'device_status_change' | 'device_data_update' | 'device_status_broadcast';
  data: DeviceStatusChange | DeviceDataUpdate | DeviceStatusBroadcast;
}

class WebSocketService {
  private socket: WebSocket | null = null;
  private reconnectAttempts = 0;
  private maxReconnectAttempts = 5;
  private reconnectTimeout: NodeJS.Timeout | null = null;
  private messageHandlers: { [key: string]: ((data: any) => void)[] } = {};
  private token: string | null = null;
  private isConnecting = false;
  private connectionCheckInterval: NodeJS.Timeout | null = null;

  constructor() {
    // 从 localStorage 获取 token
    this.token = localStorage.getItem('token');
    if (this.token) {
      this.connect();
    }
  }

  private connect() {
    if (this.isConnecting || !this.token) {
      return;
    }

    try {
      this.isConnecting = true;
      const wsHost = window.location.hostname;
      const wsPort = import.meta.env.VITE_WS_PORT || '3001';
      const wsUrl = `ws://${wsHost}:${wsPort}/ws?token=${this.token}`;

      this.socket = new WebSocket(wsUrl);

      this.socket.onopen = () => {
        console.log('WebSocket connected');
        this.isConnecting = false;
        this.reconnectAttempts = 0;
        this.startConnectionCheck();
      };

      this.socket.onclose = () => {
        console.log('WebSocket disconnected');
        this.isConnecting = false;
        this.stopConnectionCheck();
        this.handleReconnect();
      };

      this.socket.onerror = (error: Event) => {
        console.error('WebSocket error:', error);
        this.isConnecting = false;
        this.stopConnectionCheck();
        this.handleReconnect();
      };

      this.socket.onmessage = (event: MessageEvent) => {
        try {
          const message: WebSocketMessage = JSON.parse(event.data);
          this.handleMessage(message);
        } catch (error) {
          console.error('Failed to parse WebSocket message:', error);
        }
      };

    } catch (error) {
      console.error('Failed to connect to WebSocket:', error);
      this.isConnecting = false;
      this.handleReconnect();
    }
  }

  private startConnectionCheck() {
    if (this.connectionCheckInterval) {
      clearInterval(this.connectionCheckInterval);
    }
    this.connectionCheckInterval = setInterval(() => {
      if (this.socket?.readyState === WebSocket.OPEN) {
        this.socket.send(JSON.stringify({ type: 'ping' }));
      }
    }, 30000); // 每30秒发送一次心跳
  }

  private stopConnectionCheck() {
    if (this.connectionCheckInterval) {
      clearInterval(this.connectionCheckInterval);
      this.connectionCheckInterval = null;
    }
  }

  private handleMessage(message: WebSocketMessage) {
    const handlers = this.messageHandlers[message.type];
    if (handlers) {
      handlers.forEach(handler => handler(message.data));
    }
  }

  private handleReconnect() {
    if (!this.token || this.reconnectAttempts >= this.maxReconnectAttempts) {
      return;
    }

    this.reconnectAttempts++;
    const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);
    
    if (this.reconnectTimeout) {
      clearTimeout(this.reconnectTimeout);
    }

    this.reconnectTimeout = setTimeout(() => {
      console.log(`Attempting to reconnect (${this.reconnectAttempts}/${this.maxReconnectAttempts})...`);
      this.connect();
    }, delay);
  }

  public subscribe(topic: string, callback: (data: any) => void) {
    if (!this.messageHandlers[topic]) {
      this.messageHandlers[topic] = [];
    }
    this.messageHandlers[topic].push(callback);
  }

  public unsubscribe(topic: string, callback: (data: any) => void) {
    if (this.messageHandlers[topic]) {
      this.messageHandlers[topic] = this.messageHandlers[topic].filter(h => h !== callback);
    }
  }

  public send(topic: string, data: any) {
    if (this.socket?.readyState === WebSocket.OPEN) {
      this.socket.send(JSON.stringify({ type: topic, data }));
    }
  }

  public disconnect() {
    this.stopConnectionCheck();
    if (this.socket) {
      this.socket.close();
      this.socket = null;
    }
    if (this.reconnectTimeout) {
      clearTimeout(this.reconnectTimeout);
      this.reconnectTimeout = null;
    }
    this.isConnecting = false;
  }

  public updateToken(newToken: string | null) {
    this.token = newToken;
    this.disconnect();
    if (this.token) {
      this.connect();
    }
  }

  // 保存设备数据
  public async saveDeviceData(deviceId: string, data: {
    temperature?: number;
    humidity?: number;
    battery?: number;
    signal?: number;
  }): Promise<void> {
    try {
      await apiClient.post(`/devices/${deviceId}/data`, data);
    } catch (error) {
      console.error('保存设备数据失败:', error);
      throw error;
    }
  }
}

export const websocketService = new WebSocketService(); 